import numpy as np
import pandas as pd
import streamlit as st
from PIL import Image
from matplotlib import pyplot as plt
from streamlit_modal import Modal

st.header("交互操作")

# 按钮
# button方法返回一个布尔值，表示在上个应用周期按钮是否被点击。
st.subheader("---------- 按钮 ----------")
button: bool = st.button("点击我")
if button:
    st.write("今天是个好日子！")

# 复选框
# st.checkbox()：是Streamlit中用于创建复选框的函数
# 参数：
#   value默认为False，若设置为True，则复选框初始状态即为选中状态
st.subheader("---------- 复选框 ----------")
cb1: bool = st.checkbox('篮球', value=False)
cb2: bool = st.checkbox('足球', value=False)
if cb1:
    st.write('选中篮球')
else:
    st.write('取消篮球')
if cb2:
    st.write('选中足球')
else:
    st.write('取消足球')

# 单选框
# st.radio()：用于创建单选按钮组，使用户能够从一组选项中选择一个。
# 参数如下：
#   label(str):必需。单选框文本，将显示在按钮组上方，介绍单选框用途。
#   options(list,tuple,dict,orNone):必需。提供可供选择选项的列表、元组或字典。对于列表或元组，选项将按照它们在列表中的顺序显示。对于字典，将显示字典的键，并将字典的值用作用户选择的实际值。
#   index(int):可选。单选按钮组的初始选择索引，默认为0。即默认选中第一个选项。
#   format_func(function or None):可选。用于格式化选项的函数，以便在显示时进行自定义格式。
#   help(str or None):可选。为单选按钮组提供帮助文本，将在用户悬停在组件上时显示。
st.subheader("---------- 单选框 ----------")
sex = st.radio(
    label='请输入您的性别',
    options=('男', '女', '保密'),
    index=2,
    format_func=str,
    help='如果您不想透露，可以选择保密'
)

if sex == '男':
    st.write('男士您好!')
elif sex == '女':
    st.write('女士您好!')
else:
    st.write('您好!')

# 下拉框
# st.selectbox()：用于创建一个下拉选择框，使用户能够从一组选项中选择一个。
#
# st.selectbox参数与st.radio一致。
st.subheader("---------- 下拉框 ----------")
sex = st.selectbox(
    label='请输入您的性别',
    options=('男', '女', '保密'),
    index=2,
    format_func=str,
    help='如果您不想透露，可以选择保密'
)

if sex == '男':
    st.write('男士您好!')
elif sex == '女':
    st.write('女士您好!')
else:
    st.write('您好!')

# 多选框
# st.multiselect()：用于创建一个多选框，允许用户从一组选项中选择多个。

# 参数如下：
#   label:必需。多选框的标签，将显示在多选框上方，用于标识多选框的用途。
#   options:必需。提供可供选择的选项的列表、元组或字典。对于列表或元组，选项将按照它们在列表中的顺序显示。对于字典，将显示字典的键，并将字典的值用作用户选择的实际值。
#   default(list, tuple, dict,or None):可选。多选框的初始选择，默认为None。如果提供了默认值，则多选框将在初始时显示这些选项。
#   format_func:可选。用于格式化选项的函数，以便在显示时进行自定义格式。
#   help:可选。为多选框提供帮助文本，将在用户悬停在组件上时显示。

st.subheader("---------- 多选框 ----------")
options = st.multiselect(
    label='请问您喜欢吃什么水果',
    options=('橘子', '苹果', '香蕉', '草莓', '葡萄'),
    default=None,
    format_func=str,
    help='选择您喜欢吃的水果'
)

st.write('您喜欢吃的是', options)

#  滑动拉杆
# st.slider()：用于创建一个滑块，允许用户在一个范围内选择一个数值。
# 参数如下：
#   label(str):必需。滑块的标签，将显示在滑块上方，用于标识滑块的用途。
#   min_value(int, float, datetime, or None):可选。滑块的最小值。可以是整数、浮点数或datetime对象。如果未提供，则默认为0。
#   max_value(int, float, datetime, or None):可选。滑块的最大值。可以是整数、浮点数或datetime对象。如果未提供，则默认为100。
#   value(int, float, datetime, or tuple):可选。滑块的初始值。可以是单个数值或表示范围的元组。如果提供了元组，用户将能够选择一个范围而不是单个值。
#   step(int, float, or None):可选。滑块上的步进值，用户可以通过拖动滑块选择。如果未提供，则默认为1。
#   format:可选。滑块的显示格式。可以是包含"{:.2f}"之类的格式字符串，用于控制显示的小数位数。
#   key:可选。为滑块分配的唯一键，用于识别和跟踪滑块的状态变化。通常用于确保组件的稳定性。
#   help:可选。为滑块提供帮助文本，将在用户悬停在组件上时显示。

st.subheader("---------- 滑块 ----------")
age = st.slider(label='请输入您的年龄',
                min_value=0,
                max_value=100,
                value=10,
                step=1,
                help="请输入您的年龄"
                )

st.write('您的年龄是', age)

# 单行文本输入框
# streamlit.text_input函数用于创建文本输入框，允许用户输入文本信息。
# 参数如下：
#   label:必需。文本输入框的标签，将显示在输入框上方，用于标识输入框的用途。
#   value(str):可选。文本输入框的初始值，默认为空字符串。
#   max_chars(int or None):可选。文本输入框允许的最大字符数。如果未提供，则不设置字符数限制。
#   type(str):可选。输入框的类型，默认为'default'。其他选项包括'password'（密码输入框）。
#   help:可选。为文本输入框提供帮助文本，将在用户悬停在组件上时显示。
st.subheader("---------- 单行文本输入框 ----------")
name = st.text_input('请输入用户名', max_chars=100, help='最大长度为100字符', type='default')
password = st.text_input('请输入密码', max_chars=100, help='最大长度为100字符', type='password')
# 根据用户输入进行操作
st.write(f'您的用户名是:{name},密码是:{password}')

# 数字输入框
st.subheader("---------- 数字输入框 ----------")
age = st.number_input(label='请输入您的年龄',
                      min_value=0,
                      max_value=100,
                      value=0,
                      step=1,
                      help='请输入您的年龄'
                      )
st.write('您的年龄是', age)

# 多行文本输入框
st.subheader("---------- 多行文本输入框 ----------")
text = st.text_area(label='请输入文本',
                    value='请输入...',
                    height=70,
                    max_chars=200,
                    help='最大长度限制为200')

st.write('您的输入是', text)

# 日期输入框
# st.date_input()：用于创建日期输入框，允许用户选择日期。
# 参数如下：
#   label、help与前文一致
#   value(datetime.dateorNone):可选。日期输入框的初始值，应为datetime.date类型。如果未提供，则默认为None。
#   min_value(datetime.date or None):可选。日期输入框的最小值，用户不能选择早于该日期的日期。如果未提供，则不设置最小值限制。
#   max_value(datetime.date or None):可选。日期输入框的最大值，用户不能选择晚于该日期的日期。如果未提供，则不设置最大值限制。
import datetime

st.subheader("---------- 日期输入框 ----------")
birthday = st.date_input(label='请输入您的出生年月',
                         value=None,
                         min_value=None,
                         max_value=datetime.date.today(),
                         help='请输入您的出生年月')

st.write('您的生日是：', birthday)

# 时间输入框
# st.time_input()：用于创建时间输入框，允许用户选择时间。
# 参数如下：
#   label、help与前文一致。
#   value(datetime.time or None):可选。时间输入框的初始值，应为datetime.time类型。如果未提供，则默认为None。
#   step(int or timedelta)：可选。时间输入框的时间间隔。
t = st.time_input(label='请输入一个时间',
                  value=None,
                  help='请输入一个时间')

st.write('您输入的时间是：', t)

# 日期时间
st.subheader("---------- 日期时间 ----------")
# 日期选择
date = st.date_input("选择日期", value=datetime.date.today())

# 时间选择
time = st.time_input("选择时间", value=datetime.time(9, 0))

# 合并为完整的 datetime
selected_datetime = datetime.datetime.combine(date, time)

st.write("你选择的完整时间是：", selected_datetime)

# 时间范围
st.subheader("---------- 时间范围 ----------")
col1, col2 = st.columns(2)

with col1:
    start_date = st.date_input("开始日期", value=datetime.datetime.today())
    start_time = st.time_input("开始时间", value=datetime.time(9, 0))

with col2:
    end_date = st.date_input("结束日期", value=datetime.datetime.today())
    end_time = st.time_input("结束时间", value=datetime.time(17, 0))

start_datetime = datetime.datetime.combine(start_date, start_time)
end_datetime = datetime.datetime.combine(end_date, end_time)

if start_datetime >= end_datetime:
    st.error("开始时间必须早于结束时间！")
else:
    st.info(f"你选择的时间段是：\n\n{start_datetime} — {end_datetime}")

# 提示信息
# st.error: 用于显示错误消息。通常用于向用户报告发生的错误或异常。
# st.warning: 用于显示警告消息。通常用于向用户提供潜在的问题或需要注意的情况。
# st.info: 用于显示一般信息消息。可以用于提供一般性的信息或指导。
# st.success: 用于显示成功消息。通常用于向用户报告任务或操作成功完成。
# st.exception: 用于显示异常消息。当发生异常时，可以使用此函数将异常信息呈现给用户。

st.subheader("---------- 提示信息 ----------")
st.error('错误信息')

st.warning('警告信息')

st.info('提示信息')

st.success('成功信息')

st.exception('异常信息')

# 占位符
st.subheader("---------- 占位符 ----------")
placeholder = st.empty()

if st.button("显示提示"):
    with placeholder.container():
        st.warning("这是一条重要提示！", icon="⚠️")
        if st.button("关闭"):
            placeholder.empty()

# 弹出框
# pip install streamlit-modal
st.subheader("---------- 弹出框 ----------")
modal = Modal(key="Demo Modal", title="这是一个弹出框")

if st.button("打开弹窗"):
    modal.open()

if modal.is_open():
    with modal.container():
        st.write("这是弹窗里的内容！")
        if st.button("确认"):
            modal.close()

# 显示执行状态
# st.progress：用于显示一个进度条，可以设置最小值、最大值和当前值。它通常用于表示长时间运行的非阻塞任务的进度。
# st.spinner：用于显示一个旋转的加载器，表示任务正在执行。它通常用于表示短时间运行的任务的执行状态。当任务完成时，加载器将自动消失。
st.subheader("---------- 显示执行状态 ----------")
import time

progress_bar = st.empty()
for i in range(10):
    progress_bar.progress(i / 10, '进度')
    time.sleep(0.5)

with st.spinner('加载中...'):
    time.sleep(2)
